#include "transContentPacketMemoryOut.hpp"

int TransContentRecordMemoryOut::sendTo(const EndPoint* target, int flag, char* buffer, int bufferLen, int timeout, sendToSyncCallback stscb){
	if(buffer == NULL || bufferLen <= 0){
		logd_error("sendTo, parameter buffer error!");
		return E_TRANC_ParamError;
	}
	if(seding == 1){
		logd_error("sendTo, send thread is busying");
		return E_TRANC_STATE_BUSY;
	}
	this->sendData = buffer;
	this->sendDataLen = bufferLen;
	this->timeout = timeout;
	this->stscb = stscb;

	/// notice new data arrived
	newDataRecordAvaliable();

	///reurn no block
	if(this->stscb != NULL){
		logd_error("sendTo, use async style, not block the caller");
		return E_TRANC_NONBLOCK;
	}
	/// wait
	pthread_mutex_lock(&waitMutex);
	if(pthread_cond_timedwait(&waitCond, &waitMutex, &ts) == ETIMEDOUT){
		sending = 0;
		logd_error("sendTo, send timeout, will return");
		return E_TRANC_TIMEOUT;
	}
	pthread_mutex_unlock(&waitMutex);
	logd_info("sendTo, send %d length finished", bufferLen);
	return bufferLen;
}

void TransContentRecordMemoryOut::sendFinished(){
	pthread_t pid;
	if(this->stscb != NULL){
		pthread_create(&pid, NULL, finishedRoute, this);
		pthread_detach(pid);
	}else{
		pthread_mutex_lock(&waitMutex);
		pthread_cond_signal(&waitCond);
		pthread_mutex_unlock(&waitMutex);
	}
}

void* TransContentRecordMemoryOut::finishedRoute(void* p){
	(TransContentRecordMemoryOut*(p))->finishCallback();
	return NULL;
}

void TransContentRecordMemoryOut::finishCallback(){
	this->stscb(sendDataLen);
}

void TransContentRecordMemoryOut::sendWorker(){
	static pthread_mutex_t dataAvaliableMutex = PTHREAD_MUTEX_INITIALIZER;
		static pthread_cond_t dataAvalableCond = PTHREAD_COND_INITIALIZER;
	while(working){
		pthread_mutex_lock(&dataAvaliableMutex);
		pthread_cond_wait(&dataAvalableCond, &dataAvaliableMutex);
		pthread_mutex_unlock(&dataAvaliableMutex);
		sendDataOut();
	}
}

void TransContentRecordMemoryOut::sendDataOut(){
	int leftBytes = bufferLen;                                                                                                          
	int __bufferIndex = -1; 
	int __sendBytes = 0;
	int __bufferSize = TransContentSetting::getMemoryBufferSize()- 50; 
	char* __buffer;
	this->timeout = timeout;
	this->stscb = stscb;

	__bufferIndex = TransContentMemory::getInstance()->getBuffer(&__buffer);
	if(__bufferIndex < 0){ 
		logd_error("sendTo, get buffer to store data error!, no buffer avaliable");
		return __bufferIndex;
	}   
	while(leftBytes > 0){ 

		if(__bufferSize > leftBytes){
			memcpy(__buffer, buffer + __sendBytes, leftBytes);
			leftBytes = 0;
		}else{
			memcpy(__buffer, buffer + __sendBytes, __bufferSize);
			leftBytes -= __bufferSize;
			__sendBytes = __bufferSize;
		}	
		*(short*(buffer)) = __sendBytes + 20;
		buffer[2] = (char)message_type_out_data_packet; //main code
		*(NodeAddr*(buffer+3)) = target->addr; //target
		buffer[11] = (char)flag;
		*(short*(buffer+12)) = TransContentAssis::SHORTL2N(8 + __sendBytes);
		buffer[14] = (char)message_type_out_data_packet; //main code
		buffer[15] = (char)message_type_data_packet_sub_dataIn; //sub code
		*(int*(buffer+16)) = TransContentAssis::INTL2N(target->port); //port
		*(short*(buffer+20)) = TransContentAssis::SHORTL2N(__sendBytes);

		/// send to stack
		TransContentDispatcher::getInstance()->sendDataDataToStack(buffer, __sendBytes+22);
	}
	sendFinished();
	return E_TRANC_SUCESS;
}

